package modele;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

import codebase.IPartie;

public class Tour implements Serializable {
	/**
	 * phase : 1-> negociation | 2 -> ordres | 3 -> dispersion
	 */
	private static final long serialVersionUID = 1L;
	private int annee;
	private String saison;
	private int phase;
	private ArrayList<Ordre> listeOrdre;
	private ArrayList<String> listOrdreString;

	public Tour(int annee, String saison) {
		this.annee = annee;
		this.saison = saison;
		this.phase = 1;
		this.listeOrdre = new ArrayList<Ordre>();
		this.listOrdreString = new ArrayList<String>();
	}

	public boolean phaseSuivante() {
		if (phase < 3) {
			phase++;
			return true;
		} else {
			return false;
		}
	}

	public int getAnnee() {
		return annee;
	}

	public int getPhase() {
		return phase;
	}

	public int getNextAnnee() {
		if (this.saison.equals("Automne")) {
			return annee + 1;
		}
		return annee;
	}

	public String getSaison() {
		return saison;
	}

	public String getNextSaison() {
		if (this.saison.equals("Automne")) {
			return "Printemps";
		}
		return "Automne";
	}

	public String getInfo() {
		return "Année " + annee + " - " + saison;
	}

	public void addOrdre(Ordre o) {
		this.listeOrdre.add(o);
	}

	public void addOrdre(String s) {
		this.listOrdreString.add(s);
		System.out.println("Tour Ajout de " + s + "\n" + listOrdreString);
	}

	public void removeOrdre(String s) {
		this.listOrdreString.remove(s);
		System.out.println("Suppression de " + s + "\n" + listOrdreString);
	}

	public void arbitrage(Carte carte) throws RemoteException {
		System.out.println("Arbitrage");
		// this.listOrdreString = this.demandeOrdre();
		String lOrdre = "";
		for (String s : listOrdreString) {
			lOrdre += s + "\n";
		}

		ArrayList<String> blackList = new ArrayList<String>();
		HashMap<Region, ArrayList<Ordre>> listeConflit = new HashMap<Region, ArrayList<Ordre>>();
		System.out.println(listOrdreString);
		for (String s : listOrdreString) {
			Ordre o = Ordre.verifSyntaxe(s);
			// Suppression des doublons -> Plus necessaire avec l interface
			/*
			 * for (Ordre ordre : this.listeOrdre) { // Si l'ordre existe deja
			 * if (o.getRegOrigine().getAbreviation()
			 * .equalsIgnoreCase(ordre.getRegOrigine().getAbreviation())) {
			 * blackList.add(o.getRegOrigine().getAbreviation());
			 * this.listeOrdre.remove(ordre); } } if
			 * (!blackList.contains(o.getRegOrigine().getAbreviation())) {
			 * this.listeOrdre.add(o); }
			 */
			if (o != null) {
				this.listeOrdre.add(o);
			}
		}

		// Ajout des regions sans ordres
		for (String s : Carte.carte.keySet()) {
			// Voir la methode pour comparaison avec la redef de la fonction
			if (IPartie.carte.getRegion(s).getOccupant() != null) {
				boolean present = false;
				for (Ordre o : this.listeOrdre) {
					if (IPartie.carte.getRegion(s).equals(o.getRegOrigine())) {
						present = true;
					}
				}
				if (!present) {
					// Ajout de l'ordre de tenir position
					this.listeOrdre.add(new Defense(IPartie.carte.getRegion(s).getOccupant()
							.getProprietaire(), IPartie.carte.getRegion(s).getOccupant()
							.getTypeUnite(), IPartie.carte.getRegion(s)));
				}
			}
		}

		// Verifcation des croisements
		for (int i = 0; i < this.listeOrdre.size(); i++) {
			Ordre o = this.listeOrdre.get(i);
			if (o instanceof Attaque) {
				if (!o.isCroisement()) {
					for (int j = i; j < this.listeOrdre.size(); j++) {
						Ordre p = listeOrdre.get(j);
						if (p instanceof Attaque) {
							if (o.getRegOrigine().equals(p.getRegDestination())
									&& o.getRegDestination().equals(p.getRegOrigine())) {
								o.setCroisement(true);
								p.setCroisement(true);
							}
						}
					}
				}
			}
		}

		// Tri de listeOrdre (Convoi - Sout - Def - Att)
		Collections.sort(this.listeOrdre, new Comparator<Ordre>() {
			public int compare(Ordre o1, Ordre o2) {
				String s1 = "";
				if (o1 instanceof Attaque) {
					s1 = "d";
				} else if (o1 instanceof Defense) {
					s1 = "c";
				} else if (o1 instanceof Soutien) {
					s1 = "b";
				} else if (o1 instanceof Convoi) {
					s1 = "a";
				}
				String s2 = "";
				if (o2 instanceof Attaque) {
					s2 = "d";
				} else if (o2 instanceof Defense) {
					s2 = "c";
				} else if (o2 instanceof Soutien) {
					s2 = "b";
				} else if (o2 instanceof Convoi) {
					s2 = "a";
				}

				return s1.compareTo(s2);
			}
		});

		// Verification des ordres
		ArrayList<Ordre> soutienToVerif = new ArrayList<Ordre>();
		for (Ordre o : this.listeOrdre) {
			if (o instanceof Convoi) {
				if (o.verifValidite()) {
					for (Ordre ordre : this.listeOrdre) {
						if (((Convoi) o).getRegionConvoye().equals(ordre.getRegOrigine())) {
							ordre.addConvoi(o);
							break;
						}
					}
				}
				Ordre or = new Defense(o.getCommanditaire(), o.getTypeUnite(), o.getRegOrigine());
				if (listeConflit.containsKey(or.getRegOrigine())) {
					listeConflit.get(or.getRegOrigine()).add(or);
				} else {
					ArrayList<Ordre> oListe = new ArrayList<Ordre>();
					oListe.add(or);
					listeConflit.put(or.getRegOrigine(), oListe);
				}
			} else if (o instanceof Soutien) {
				if (o.verifValidite()) {
					soutienToVerif.add(o);
				} else {
					Ordre or = new Defense(o.getCommanditaire(), o.getTypeUnite(),
							o.getRegOrigine());
					if (listeConflit.containsKey(or.getRegOrigine())) {
						listeConflit.get(or.getRegOrigine()).add(or);
					} else {
						ArrayList<Ordre> oListe = new ArrayList<Ordre>();
						oListe.add(or);
						listeConflit.put(or.getRegOrigine(), oListe);
					}
				}
			} else if (o instanceof Defense) {
				if (listeConflit.containsKey(o.getRegOrigine())) {
					listeConflit.get(o.getRegOrigine()).add(o);
				} else {
					ArrayList<Ordre> oListe = new ArrayList<Ordre>();
					oListe.add(o);
					listeConflit.put(o.getRegOrigine(), oListe);
				}
			} else if (o instanceof Attaque) {
				if (o.verifValidite()) {
					if (listeConflit.containsKey(o.getRegDestination())) {
						listeConflit.get(o.getRegDestination()).add(o);
					} else {
						ArrayList<Ordre> oListe = new ArrayList<Ordre>();
						oListe.add(o);
						listeConflit.put(o.getRegDestination(), oListe);
					}
				} else {
					if (listeConflit.containsKey(o.getRegOrigine())) {
						listeConflit.get(o.getRegOrigine()).add(o);
					} else {
						ArrayList<Ordre> oListe = new ArrayList<Ordre>();
						oListe.add(o);
						listeConflit.put(o.getRegOrigine(), oListe);
					}
				}
			}
		}
		ArrayList<Ordre> toDelete = new ArrayList<Ordre>();
		boolean attaque = false;
		for (Ordre o : soutienToVerif) {
			attaque = false;
			if (listeConflit.containsKey(o.getRegOrigine())) {
				for (Ordre ordre : listeConflit.get(o.getRegOrigine())) {
					if (ordre instanceof Attaque) {
						toDelete.add(o); // TODO check la
						attaque = true;
					}
				}
			}
			if (!attaque) {
				for (Ordre ord : this.listeOrdre) {
					if (ord.equals(o)) {
						ord.incrementeForce();
					}
				}
			}
		}
		// Pour chaque Soutient attaque on l'ajoute en tenir position dans son
		// territoire
		for (Ordre o : toDelete) {
			Ordre or = new Defense(o.getCommanditaire(), o.getTypeUnite(), o.getRegOrigine());
			if (listeConflit.containsKey(or.getRegOrigine())) {
				listeConflit.get(or.getRegOrigine()).add(or);
			} else {
				ArrayList<Ordre> oListe = new ArrayList<Ordre>();
				oListe.add(or);
				listeConflit.put(or.getRegOrigine(), oListe);
			}
		}
		// todo : On trie l'hashMap en fonction de la taille ArrayList<Ordre>
		// pour les croisements
		// voir excel
		ArrayList<Region> listeRetraite = new ArrayList();
		for (Region region : listeConflit.keySet()) {
			if (listeConflit.get(region).size() == 1) {
				if (listeConflit.get(region).get(0).getTypeOrdre().equals("Attaque")) {
					carte.getRegion(
							listeConflit.get(region).get(0).getRegDestination().getAbreviation()
									.toLowerCase()).setOccupant(
							listeConflit.get(region).get(0).getRegOrigine().getOccupant());
					carte.getRegion(
							listeConflit.get(region).get(0).getRegOrigine().getAbreviation()
									.toLowerCase()).getOccupant().getProprietaire()
							.addRegion(listeConflit.get(region).get(0).getRegDestination());

					carte.getRegion(
							listeConflit.get(region).get(0).getRegOrigine().getAbreviation()
									.toLowerCase()).setOccupant(null);
				}
				System.out.println("Odre :"
						+ listeConflit.get(region).get(0).getRegOrigine().getNom() + "--regDes-->"
						+ region.getNom());
			} else {
				int ptAtt = 0;
				int ptDef = 0;
				int cAttaquant = 0;
				for (Ordre o : listeConflit.get(region)) {
					if (o instanceof Defense) {
						ptDef = o.getForce();
						cAttaquant++;
					} else if (o instanceof Attaque) {
						ptAtt = o.getForce();
					}
				}
				if (ptAtt > ptDef) {
					if (listeConflit.get(region).get(0).getForce() > listeConflit.get(region)
							.get(1).getForce()) {
						carte.getRegion(
								listeConflit.get(region).get(0).getRegDestination()
										.getAbreviation().toLowerCase()).setOccupant(
								listeConflit.get(region).get(0).getRegOrigine().getOccupant());
						carte.getRegion(
								listeConflit.get(region).get(0).getRegOrigine().getAbreviation()
										.toLowerCase()).getOccupant().getProprietaire()
								.addRegion(listeConflit.get(region).get(0).getRegDestination());

						carte.getRegion(
								listeConflit.get(region).get(0).getRegOrigine().getAbreviation()
										.toLowerCase()).setOccupant(null);
					} else {
						carte.getRegion(
								listeConflit.get(region).get(1).getRegDestination()
										.getAbreviation().toLowerCase()).setOccupant(
								listeConflit.get(region).get(1).getRegOrigine().getOccupant());
						carte.getRegion(
								listeConflit.get(region).get(1).getRegOrigine().getAbreviation()
										.toLowerCase()).getOccupant().getProprietaire()
								.addRegion(listeConflit.get(region).get(0).getRegDestination());

						carte.getRegion(
								listeConflit.get(region).get(1).getRegOrigine().getAbreviation()
										.toLowerCase()).setOccupant(null);
					}
					System.out.println("Ici " + region.getNom() + " L'attaque remporte");
					System.out.println(region.getOccupant() + " doit battre en retraire");
					listeRetraite.add(region);
				} else {
					System.out.println("Ici " + region + " tombe a l'eau");
				}
				// JOptionPane.showMessageDialog(new JFrame("Diplomacy"),
				// "Resultat" + "\n");
				// si ordre.type = defense et force def < force total de toutes
				// les attaques
				// ajout dans arraylist listeRetraite
				// sinon si ordre.type = attaque et ordre.force > forces des
				// autres ordre
				// effectuer action
			}
		}
		System.out.println("Fin arbitrage");
	}

	public ArrayList<String> demandeOrdre() {
		ArrayList<String> l = new ArrayList<String>();

		l.add("FR A GAS T");
		l.add("GB A BOU - GAS");
		l.add("AL A BEL - BOU");
		l.add("FR A KIE - MUN");
		l.add("GB A MUN - KIE");
		l.add("FR A TRI - BUD");
		l.add("GB A BUD - TRI");
		l.add("FR A SER S TRI - BUD");
		l.add("FR A LIT - MOS");
		l.add("FR A STP S LIT - MOS");
		l.add("GB A MOS - LIT");
		l.add("GB A VAR S MOS - LIT");
		l.add("FR A UKR - VAR");
		l.add("GB A ANK - CON");
		l.add("FR  A CON - SMY");
		l.add("AL A SMY - SYR");
		l.add("RU A SYR - CAU");
		l.add("FR A ESP - MAR");
		l.add("AH F MED C ESP - MAR");
		l.add("RU F LIO - MED");
		l.add("RU F TYR S LIO - MED");
		l.add("FR F GRO - ISL");
		l.add("AH F ISL T");
		l.add("FR F STG S GRO - ISL");

		return l;
	}
}
